﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DataProcessing
{
    /// <summary>
    /// 以平凡算法验证快速算法的正确性
    /// </summary>
    public class EvenValidator
    {
        public class Mismatch
        {
            public CalculationCache Cache;
            public uint evenSum;
            public uint chrIndex;
            public uint cacheIndex;
            public long bias;
        }
        public static bool Validate(string fileName)
        {
            ChromePairData.Data = BedFileParser.GetFromFile(fileName);
            
            ChromePairData.Initialize();
            
            UInt16[] evenValues = new UInt16[ChromePairData.AllWindowMax.Size];
              //for all chromes
            for(int i=0;i<ChromePairData.Data.Length;i++)
            {
                ChromePairData currentData = ChromePairData.Data[i];
                
                
                CalculateValues_EVEN(evenValues, currentData);

                 //for all cache items,compare accumulations got from fast 
                //calculation and even calculation
                int j = 0;
                
                for (j = 0; j < currentData.CurrentCache.Length; j++)
                {

                    uint start = currentData.CurrentCache[j].Window.Start;
                    uint end = Math.Min(currentData.CurrentCache[j].Window.End, ChromePairData.AllWindowMax.End);
                    uint sumFromEven = GetAccumulation_EVEN(evenValues, start, end);
                    if (sumFromEven != currentData.CurrentCache[j].Accumulation)
                    {
                        handleMismatch(evenValues, i, currentData, j, sumFromEven);
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// 算出在某个区间上的分布
        /// </summary>
        /// <param name="values"></param>
        /// <param name="currentData"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        private static uint GetAccumulation_EVEN(UInt16[] values, uint start, uint end)
        {
            uint sumFromEven = 0;
            for (uint q = start;
                q <= end;
                q++)
            {
                sumFromEven += values[q - ChromePairData.AllWindowMax.Start];

            }
            return sumFromEven;
        }

        /// <summary>
        /// 算出每个点上的分布
        /// </summary>
        /// <param name="evenValues"></param>
        /// <param name="currentData"></param>
        private static void CalculateValues_EVEN(UInt16[] evenValues, ChromePairData currentData)
        {
            int i = 0;
            for (i = 0; i < evenValues.Length; i++)
            {
                evenValues[i] = 0;
            }
            //for all samplings for this chrome, caculate even values.
            for (i = 0; i < currentData.ChromeSampling.Count; i++)
            {
                ChrSampling currentSampling = currentData.ChromeSampling[i];
                for (uint q = currentSampling.Begin; q <= currentSampling.End; q++)
                {
                    evenValues[q - ChromePairData.AllWindowMax.Start]++;
                }
            }
            
        }

        /// <summary>
        /// only for error case，理论上完全可以不存在本方法，仅为出错时候调试方便
        /// </summary>
        /// <param name="evenValues"></param>
        /// <param name="i"></param>
        /// <param name="currentData"></param>
        /// <param name="j"></param>
        /// <param name="sumFromEven"></param>
        private static void handleMismatch(UInt16[] evenValues, int i, ChromePairData currentData, int j, uint sumFromEven)
        {
            
            List<Mismatch> mismatch = new List<Mismatch>();

            UInt16[] localValues = new UInt16[ChromePairData.AllWindowMax.Size];
            uint sumFromLocalOverlap = 0;
            for (int sampleIndex = 0; sampleIndex < currentData.CurrentCache[j].SamplesFallingIn.Count; sampleIndex++)
            {
                ChrSampling currentSampling = currentData.CurrentCache[j].SamplesFallingIn[sampleIndex];
                uint valueStart = Math.Max(currentSampling.Begin, currentData.CurrentCache[j].Window.Start);
                uint valueEnd = Math.Min(currentSampling.End, currentData.CurrentCache[j].Window.End);
                uint accumuFromEven = 0;
                accumuFromEven = 0;
                for (uint valueIndex = valueStart; valueIndex <= valueEnd; valueIndex++)
                {

                    localValues[valueIndex - currentData.CurrentWindow.Start]++;
                    accumuFromEven++;
                }
                sumFromLocalOverlap += currentData.CurrentCache[j].Window.OverlappedLength(currentSampling.Window);
                if (accumuFromEven != currentData.CurrentCache[j].Window.OverlappedLength(currentSampling.Window))
                {
                    int a = 0;
                    a++;
                }
            }

            uint start = currentData.CurrentCache[j].Window.Start - currentData.CurrentWindow.Start;
            uint end = currentData.CurrentCache[j].Window.End - currentData.CurrentWindow.Start;

            uint sumFromLocalEven = 0;
            for (uint valueIndex = start; valueIndex <= end; valueIndex++)
            {
                if (localValues[valueIndex] != evenValues[valueIndex])
                {
                    int a = 0;
                    a++;
                }
                sumFromLocalEven += localValues[valueIndex];
            }
            mismatch.Add(new Mismatch { bias = sumFromEven - currentData.CurrentCache[j].Accumulation, Cache = currentData.CurrentCache[j], chrIndex = (uint)i, evenSum = sumFromEven, cacheIndex = (uint)j });

        }
    }

}
